#include "dialogs.h"
#include "graph.h"
#include "config-fnt.h"
#include "misc.h"
#include <QtWidgets/QtWidgets>
#include <memory>

bool PositionDialog::getPosition(Point* pos, const std::array<double, 6>& bbox, QWidget* par) {
	std::unique_ptr<PositionDialog> dlg{new PositionDialog(pos, bbox, par)};
	
	bool res=dlg->exec()==QDialog::Accepted;
	if(res) {
		pos->x(dlg->spinBoxes[0]->value());
		pos->y(dlg->spinBoxes[1]->value());
		pos->z(dlg->spinBoxes[2]->value());
	}
	return res;
}
void PositionDialog::copy2ClipboardClicked() {
	QString source = QString::number(spinBoxes[0]->value()) + ";"+ QString::number(spinBoxes[1]->value()) + ";"+ QString::number(spinBoxes[2]->value()) + ";";
	QClipboard *clipboard = QApplication::clipboard();   //获取系统剪贴板指针
	QString originalText = clipboard->text();         //获取剪贴板上文本信息
	clipboard->setText(source);

}

void PositionDialog::copyFromClipboardClicked()
{
	QClipboard *clipboard = QApplication::clipboard();  
	QString originalText = clipboard->text();     
	QStringList values = originalText.split(";");
	if (values.length() == 4 || values.length() == 3) {
		std::cout << values.length() << "\t" << values[0] << "\t" << values[1] << "\t" << values[2] << std::endl;
		spinBoxes[0]->setValue(values[0].toDouble());
		spinBoxes[1]->setValue(values[1].toDouble());
		spinBoxes[2]->setValue(values[2].toDouble());
	}
}

PositionDialog::PositionDialog(Point* pos, const std::array<double, 6>& bbox, QWidget* par):
	QDialog{par}, _bbox(bbox)
{
	std::array<double, 3> vals{pos->x(), pos->y(), pos->z()};
	for(int i=0; i<3; i++) {
		if(_bbox[i*2]>_bbox[i*2+1])
			_bbox[i*2]=_bbox[i*2+1]=vals[i];
		if(_bbox[2*i]==_bbox[2*i+1]) {
			_bbox[2*i]-=1;
			_bbox[2*i+1]+=1;
		}
	}

	setWindowTitle("Pick a position");

	QGridLayout* layout=new QGridLayout(this);
	layout->setColumnStretch(1, 1);
	layout->setRowStretch(3, 1);

	QLabel* label;
	label=new QLabel("X: ", this);
	layout->addWidget(label, 0, 0, 1, 1);
	label->setAlignment(Qt::AlignRight|Qt::AlignBaseline);
	label=new QLabel("Y: ", this);
	layout->addWidget(label, 1, 0, 1, 1);
	label->setAlignment(Qt::AlignRight|Qt::AlignBaseline);
	label=new QLabel("Z: ", this);
	layout->addWidget(label, 2, 0, 1, 1);
	label->setAlignment(Qt::AlignRight|Qt::AlignBaseline);
	label = new QLabel("Choose X, Y, Z coordinates to pick a position.(ex:3000;4000;5000)", this);
	layout->addWidget(label, 3, 0, 1, 4);
	label->setAlignment(Qt::AlignLeft|Qt::AlignBaseline);
	label->setWordWrap(true);

	//


	for(int i=0; i<3; i++) {
		sliders[i]=new QSlider(Qt::Horizontal, this);
		layout->addWidget(sliders[i], i, 1, 1, 2);
		sliders[i]->setTickPosition(QSlider::NoTicks);
		sliders[i]->setMinimum(0);
		sliders[i]->setSingleStep(100);
		sliders[i]->setMaximum(10000);
		sliders[i]->setMinimumWidth(120);
		sliders[i]->setValue(lrint(10000*(vals[i]-_bbox[2*i])/(_bbox[2*i+1]-_bbox[2*i])));
		connect(sliders[i], &QSlider::valueChanged, [this, i](int v) { this->sliderChanged(i, v); });

		spinBoxes[i]=new QDoubleSpinBox(this);
		layout->addWidget(spinBoxes[i], i, 3, 1, 1);
		//spinBoxes[i]->setDecimals(2);
		spinBoxes[i]->setMinimum(_bbox[2*i]);
		spinBoxes[i]->setSingleStep(0.1);
		spinBoxes[i]->setMaximum(_bbox[2*i+1]);
		spinBoxes[i]->setValue(vals[i]);
		spinBoxes[i]->setSuffix("µm");
		spinBoxes[i]->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
		spinBoxes[i]->setAccelerated(true);
		connect(spinBoxes[i], static_cast<void (QDoubleSpinBox::*)(double)>(&QDoubleSpinBox::valueChanged), [this, i](double v) { this->spinBoxChanged(i, v); });
	}
	QPushButton *copy2Clipboard = new QPushButton("Copy to ClipBoard", this);
	QPushButton *copyFromClipboard=new QPushButton("Copy From ClipBoard",this);
	auto btnBox=new QDialogButtonBox{QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal, this};
	layout->addWidget(copy2Clipboard, 4, 0, 1, 2);
	layout->addWidget(copyFromClipboard, 4, 2, 1, 2);
	layout->addWidget(btnBox, 5, 1, 1, 3);
	connect(btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
	connect(btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
	connect(copy2Clipboard, SIGNAL(clicked()), this, SLOT(copy2ClipboardClicked()));
	connect(copyFromClipboard, SIGNAL(clicked()), this, SLOT(copyFromClipboardClicked()));
	btnBox->button(QDialogButtonBox::Ok)->setAutoDefault(true);


}


template<typename T, typename V>
static void setValueNoSignal(T* obj, V val) {
	bool prev=obj->blockSignals(true);
	obj->setValue(val);
	obj->blockSignals(prev);
}
void PositionDialog::sliderChanged(int i, int value) {
	setValueNoSignal(spinBoxes[i], _bbox[2*i]+value*(_bbox[2*i+1]-_bbox[2*i])/10000);
}
void PositionDialog::spinBoxChanged(int i, double d) {
	setValueNoSignal(sliders[i], lrint(10000*(d-_bbox[2*i])/(_bbox[2*i+1]-_bbox[2*i])));
}

LoginInfoDialog::LoginInfoDialog(const QUrl& url, QWidget* par):
	QDialog{par}
{
	setWindowTitle("Login information");
	//setWindowIcon(QIcon("logininfo"));
	QGridLayout* layout=new QGridLayout(this);
	layout->setColumnStretch(1, 1);
	layout->setRowStretch(2, 1);

	QLabel* label;
	label=new QLabel("Username: ", this);
	layout->addWidget(label, 0, 0, 1, 1);
	label=new QLabel("Password: ", this);
	layout->addWidget(label, 1, 0, 1, 1);
	label=new QLabel("Please specify login information to URL: "+url.toString()+". This information will be kept in momory and used latter.", this);
	layout->addWidget(label, 2, 0, 1, 2);
	label->setWordWrap(true);

	lineUsr=new QLineEdit(this);
	layout->addWidget(lineUsr, 0, 1, 1, 1);
	lineUsr->setClearButtonEnabled(true);
	linePwd=new QLineEdit(this);
	layout->addWidget(linePwd, 1, 1, 1, 1);
	linePwd->setClearButtonEnabled(true);
	linePwd->setEchoMode(QLineEdit::Password);
	linePwd->setMinimumWidth(120);

	auto btnBox=new QDialogButtonBox{QDialogButtonBox::Ok|QDialogButtonBox::Cancel, Qt::Horizontal, this};
	layout->addWidget(btnBox, 3, 0, 1, 2);
	connect(btnBox, &QDialogButtonBox::accepted, this, &QDialog::accept);
	connect(btnBox, &QDialogButtonBox::rejected, this, &QDialog::reject);
	btnBox->button(QDialogButtonBox::Ok)->setAutoDefault(true);

}
bool LoginInfoDialog::getLoginInfo(QString* usr, QString* pwd, const QUrl& url) {
	std::unique_ptr<LoginInfoDialog> dlg{new LoginInfoDialog(url, nullptr)};
	dlg->lineUsr->setText(*usr);
	dlg->linePwd->setText(*pwd);
	bool res=dlg->exec()==QDialog::Accepted;
	if(res) {
		*usr=dlg->lineUsr->text();
		*pwd=dlg->linePwd->text();
	}
	return res;
}

AboutDlg::AboutDlg(QWidget* par):
	QDialog{par, 0}
{
	auto vlayout=new QVBoxLayout(this);

	auto iconBtn=new QLabel{this};
	vlayout->addWidget(iconBtn, 0, Qt::AlignHCenter);
	iconBtn->setPixmap(QPixmap{":/images/generated/icon.svg"});
	iconBtn->setScaledContents(true);
	iconBtn->setMinimumSize(128, 128);
	iconBtn->setMaximumSize(128, 128);

	auto label=new QLabel("<big><b>" PACKAGE_NAME_LONG "</b></big>", this, 0);
	vlayout->addWidget(label, 0, Qt::AlignHCenter);

	label=new QLabel("<code>" PACKAGE_VERSION "</code>", this, 0);
	vlayout->addWidget(label, 0, Qt::AlignHCenter);

	label=new QLabel("<i>" PACKAGE_DESCRIPTION "</i>", this, 0);
	vlayout->addWidget(label, 0, Qt::AlignHCenter);


	label=new QLabel("<a href='" PACKAGE_URL "'>Homepage</a> (<a href='" PACKAGE_BUGREPORT "'>Report Bugs</a>)", this, 0);
	vlayout->addWidget(label, 0, Qt::AlignHCenter);
	label->setOpenExternalLinks(true);

	vlayout->addStretch(1);

	auto w=par->windowHandle();
	
	auto c=QOpenGLContext::globalShareContext();
	c->makeCurrent(w);
	auto funcs=c->functions();
	QString glVen{reinterpret_cast<const char*>(funcs->glGetString(GL_VENDOR))};
	QString glVer{reinterpret_cast<const char*>(funcs->glGetString(GL_VERSION))};
	QString glRen{reinterpret_cast<const char*>(funcs->glGetString(GL_RENDERER))};
	c->doneCurrent();
	label=new QLabel("<small>"
			+QSysInfo::currentCpuArchitecture()
			+" | "+QSysInfo::prettyProductName()
			+" | Qt "+qVersion()+" (" QT_VERSION_STR ")"
			+"</small>", this, 0);
	vlayout->addWidget(label, 0, Qt::AlignHCenter);
	label=new QLabel("<small>"
			+glVen
			+" | "+glVer
			+" | "+glRen
			+"</small>", this, 0);
	vlayout->addWidget(label, 0, Qt::AlignHCenter);

	label=new QLabel("<small>Copyright © 2024 "+QString{PACKAGE_AUTHORS}.replace(QRegExp{"<([^@>]+@[^@>]+)>"}, "<a href='mailto:\\1'>@</a>")+"</small>", this, 0);
	vlayout->addWidget(label, 0, Qt::AlignHCenter);
	label->setOpenExternalLinks(true);

	label=new QLabel("<small>" PACKAGE_ORG "</small>", this, 0);
	vlayout->addWidget(label, 0, Qt::AlignHCenter);

	layout()->setSizeConstraint(QLayout::SetFixedSize);
}
AboutDlg::~AboutDlg() {
}

bool CreateSessionDialog::getLocation(QWidget* par, QString* loc, std::array<double, 3>* p0, std::array<double, 9>* dir) {
	CreateSessionDialog dlg{par, *loc, *p0, *dir};
	if(dlg.exec()!=QDialog::Accepted)
		return false;
	*loc=dlg.lineLoc->text();
	for(int i=0; i<3; i++)
		(*p0)[i]=dlg.spinP0[i]->text().toDouble();
	for(int i=0; i<9; i++)
		(*dir)[i]=dlg.spinDir[i]->text().toDouble();
	return true;
}

/*
class CreateSessionDialog : public QDialog {
	QDoubleSpinBox* spinP0[3];
	QDoubleSpinBox* spinDir[9];
	QDoubleSpinBox* spinRes[3];
	CreateSessionDialog::~CreateSessionDialog();

	void CreateSessionDialog::spinResChanged(int i, double v);
	void CreateSessionDialog::spinDirChanged(int i, double v);

	private Q_SLOTS:
		void CreateSessionDialog::openFileClicked();
	void CreateSessionDialog::createClicked();
	void CreateSessionDialog::cancelClicked();
}
*/
CreateSessionDialog::CreateSessionDialog(QWidget* par, const QString& loc, const std::array<double, 3>& p0, const std::array<double, 9>& dir):
	QDialog{par, 0}
{
	auto vlayout=new QVBoxLayout{this};
	auto hlayoutUrl=new QHBoxLayout{};
	vlayout->addLayout(hlayoutUrl, 0);

	auto label=new QLabel{"&Location:", this};
	hlayoutUrl->addWidget(label, 0);
	lineLoc=new QLineEdit{loc, this};
	hlayoutUrl->addWidget(lineLoc, 1);
	label->setBuddy(lineLoc);
	lineLoc->setClearButtonEnabled(true);
	lineLoc->setMinimumWidth(120);

	auto btnCache=new QPushButton{QIcon{":/images/breeze/document-open.svg"}, "", this};
	hlayoutUrl->addWidget(btnCache, 0);
	connect(btnCache, &QPushButton::clicked, this, &CreateSessionDialog::openFileClicked);

	auto hlayoutBtn=new QHBoxLayout{};
	vlayout->addLayout(hlayoutBtn, 0);

	auto widget=new QGroupBox{"Transformation", this};
	vlayout->addWidget(widget, 0);
	vlayout->addStretch(1);
	//widget->setVisible(false);

	auto vlayout2=new QVBoxLayout{widget};
	auto gridlayout=new QGridLayout{};
	vlayout2->addLayout(gridlayout, 0);

	auto validator=new QDoubleValidator{this};
	for(int i=0; i<9; i++) {
		auto x=i/3;
		auto y=i%3;
		spinDir[i]=new QLineEdit{QString::number(dir[i], 'g', 3), widget};
		gridlayout->addWidget(spinDir[i], 0+y, 0+x, 1, 1);
		spinDir[i]->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
		spinDir[i]->setValidator(validator);
		spinDir[i]->setMinimumWidth(64);
		spinDir[i]->setMaximumWidth(64);
	}
	auto line=new QFrame{widget};
	gridlayout->addWidget(line, 0, 3, 3, 1);
	line->setFrameShape(QFrame::VLine);
	for(int i=0; i<3; i++) {
		spinP0[i]=new QLineEdit{QString::number(p0[i], 'g', 3), widget};
		gridlayout->addWidget(spinP0[i], i, 4, 1, 1);
		spinP0[i]->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
		spinP0[i]->setValidator(validator);
		spinP0[i]->setMinimumWidth(64);
		spinP0[i]->setMaximumWidth(64);
	}

	label=new QLabel{"Explanation of <a href='https://en.wikipedia.org/wiki/Affine_transformation'>Affine transformation</a> at Wikipedia.", widget};
	vlayout2->addWidget(label);
	label->setOpenExternalLinks(true);

	lineLoc->setWhatsThis("URL to local or remote catalog file.\nRemote files with protocols supported by libCURL should be OK.\nIf username or password are given, they will be saved to session file. Omitted; you'll be asked the first time accessing remote files and they are not saved.");

	//auto checkBox=new QCheckBox{"&Transformation", this};
	//hlayoutBtn->addWidget(checkBox, 0);
	//checkBox->setChecked(false);
	//connect(checkBox, &QCheckBox::toggled, widget, &QWidget::setVisible);

	hlayoutBtn->addStretch(1);

	auto btnCreate=new QPushButton(QIcon{":/images/breeze/document-new.svg"}, "&Create", this);
	hlayoutBtn->addWidget(btnCreate, 0);
	btnCreate->setDefault(true);
	connect(btnCreate, &QPushButton::clicked, this, &CreateSessionDialog::createClicked);

	auto btnCancel=new QPushButton(QIcon{":/images/breeze/dialog-cancel.svg"}, "&Cancel", this);
	hlayoutBtn->addWidget(btnCancel, 0);
	connect(btnCancel, &QPushButton::clicked, this, &CreateSessionDialog::cancelClicked);
	
}
CreateSessionDialog::~CreateSessionDialog() {
}

void CreateSessionDialog::createClicked() {
	auto loc=lineLoc->text();
	if(loc.endsWith(QLatin1String{"/catalog"}, Qt::CaseInsensitive)) {
	} else if(loc.compare(QLatin1String{"catalog"}, Qt::CaseInsensitive)==0) {
	} else if(loc.endsWith(QLatin1String{".tiff"}, Qt::CaseInsensitive)) {
	} else if(loc.endsWith(QLatin1String{".tif"}, Qt::CaseInsensitive)) {
#ifdef WITH_VP9
	} else if(loc.endsWith(QLatin1String{".webm"}, Qt::CaseInsensitive)) {
#endif
#ifdef WITH_HEVC
	} else if(loc.endsWith(QLatin1String{".hevc"}, Qt::CaseInsensitive)) {
#endif
	} else if(loc.endsWith(QLatin1String{".nrrd"}, Qt::CaseInsensitive)) {
	} else {
		showWarning("Create session", "Location not supported.\nPlease specify a catalog file, or an image file with extension tif/tiff/webm/nrrd.", this);
		return;
	}
	QUrl url{loc};
	if(!url.isValid()) {
		QFile d{loc};
		if(!d.exists()) {
			showWarning("Create session", "Local file not exist.", this);
			return;
		}
	}
	std::array<double, 9> dir;
	for(int i=0; i<9; i++) {
		dir[i]=spinDir[i]->text().toDouble();
	}
	auto ok=checkSingularity(dir);
	if(!ok) {
		showWarning("Create session", "Transformation matrix is probably singular.", this);
		return;
	}
	accept();
}
void CreateSessionDialog::cancelClicked() {
	reject();
}

void CreateSessionDialog::openFileClicked() {
	QFileDialog dlg(this, "Choose cache directory", lineLoc->text());
	dlg.setAcceptMode(QFileDialog::AcceptOpen);
	dlg.setFileMode(QFileDialog::ExistingFile);
	dlg.setNameFilters({"Catalog file (catalog)",
			"TIFF file (*.tif *.tiff)",
#ifdef WITH_VP9
			"WEBM file (*.webm)",
#endif
#ifdef WITH_HEVC
			"HEVC file (*.hevc)",
#endif
			"NRRD file (*.nrrd)"});
	if(dlg.exec()!=QDialog::Accepted)
		return;
	lineLoc->setText(dlg.selectedFiles()[0]);
}

